1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #include "OSPreferences.h"
13 #include "unicode/uloc.h"
15 using namespace mozilla::intl;
17 OSPreferences::OSPreferences() = default;
19 OSPreferences::~OSPreferences() = default;
21 bool OSPreferences::ReadSystemLocales(nsTArray<nsCString>& aLocaleList) {
22 MOZ_ASSERT(aLocaleList.IsEmpty());
24 nsAutoCString defaultLang(uloc_getDefault());
26 if (CanonicalizeLanguageTag(defaultLang)) {
27 aLocaleList.AppendElement(defaultLang);
33 bool OSPreferences::ReadRegionalPrefsLocales(nsTArray<nsCString>& aLocaleList) {
34 MOZ_ASSERT(aLocaleList.IsEmpty());
36 // For now we're just taking the LC_TIME from POSIX environment for all
37 // regional preferences.
38 nsAutoCString localeStr(setlocale(LC_TIME, nullptr));
40 if (CanonicalizeLanguageTag(localeStr)) {
41 aLocaleList.AppendElement(localeStr);
49 * This looks up into gtk settings for hourCycle format.
51 * This works for all GUIs that use gtk settings like Gnome, Elementary etc.
52 * Ubuntu does not use those settings so we'll want to support them separately.
54 * We're taking the current 12/24h settings irrelevant of the locale, because
55 * in the UI user selects this setting for all locales.
57 typedef GVariant* (*get_value_fn_t)(GSettings*, const gchar*);
59 static get_value_fn_t FindGetValueFunction() {
60 get_value_fn_t fn = reinterpret_cast<get_value_fn_t>(
61 dlsym(RTLD_DEFAULT, "g_settings_get_user_value"));
62 return fn ? fn : &g_settings_get_value;
65 static int HourCycle() {
70 const char* env = getenv("XDG_CURRENT_DESKTOP");
71 if (env && strcmp(env, "Unity") == 0) {
72 schema = "com.canonical.indicator.datetime";
75 schema = "org.gnome.desktop.interface";
79 // This is a workaround for old GTK versions.
80 // Once we bump the minimum version to 2.40 we should replace
81 // this with g_settings_schme_source_lookup.
82 // See bug 1356718 for details.
83 const char* const* schemas = g_settings_list_schemas();
84 GSettings* settings = nullptr;
86 for (uint32_t i = 0; schemas[i] != nullptr; i++) {
87 if (strcmp(schemas[i], schema) == 0) {
88 settings = g_settings_new(schema);
94 // We really want to use g_settings_get_user_value which will
95 // only want to take it if user manually changed the value.
96 // But this requires glib 2.40, and we still support older glib versions,
97 // so we have to check whether it's available and fall back to the older
98 // g_settings_get_value if not.
99 static get_value_fn_t sGetValueFunction = FindGetValueFunction();
100 GVariant* value = sGetValueFunction(settings, key);
102 if (g_variant_is_of_type(value, G_VARIANT_TYPE_STRING)) {
103 const char* strVal = g_variant_get_string(value, nullptr);
104 if (strncmp("12", strVal, 2) == 0) {
106 } else if (strncmp("24", strVal, 2) == 0) {
110 g_variant_unref(value);
112 g_object_unref(settings);
118 * Since Gtk does not provide a way to customize or format date/time patterns,
119 * we're reusing ICU data here, but we do modify it according to the only
120 * setting Gtk gives us - hourCycle.
122 * This means that for gtk we will return a pattern from ICU altered to
123 * represent h12/h24 hour cycle if the user modified the default value.
125 * In short, this should work like this:
127 * * gtk defaults, pl: 24h
128 * * gtk defaults, en: 12h
136 bool OSPreferences::ReadDateTimePattern(DateTimeFormatStyle aDateStyle,
137 DateTimeFormatStyle aTimeStyle,
138 const nsACString& aLocale,
139 nsAString& aRetVal) {
140 nsAutoString skeleton;
141 if (!GetDateTimeSkeletonForStyle(aDateStyle, aTimeStyle, aLocale, skeleton)) {
145 // Customize the skeleton if necessary to reflect user's 12/24hr pref
146 switch (HourCycle()) {
148 // If skeleton contains 'H' or 'k', replace with 'h' or 'K' respectively,
149 // and add 'a' unless already present.
150 if (skeleton.FindChar('H') == -1 && skeleton.FindChar('k') == -1) {
151 break; // nothing to do
154 for (size_t i = 0; i < skeleton.Length(); ++i) {
155 switch (skeleton[i]) {
160 skeleton.SetCharAt('h', i);
163 skeleton.SetCharAt('K', i);
168 skeleton.Append(char16_t('a'));
173 // If skeleton contains 'h' or 'K', replace with 'H' or 'k' respectively,
174 // and delete 'a' if present.
175 if (skeleton.FindChar('h') == -1 && skeleton.FindChar('K') == -1) {
176 break; // nothing to do
178 for (int32_t i = 0; i < int32_t(skeleton.Length()); ++i) {
179 switch (skeleton[i]) {
185 skeleton.SetCharAt('H', i);
188 skeleton.SetCharAt('k', i);
195 if (!GetPatternForSkeleton(skeleton, aLocale, aRetVal)) {